/**
 * 
 */
package org.codesketch.birch.command;

import java.security.InvalidParameterException;
import java.util.Properties;
import java.util.Set;

import org.codesketch.birch.common.BirchRequest;
import org.codesketch.birch.common.BirchResponse;
import org.codesketch.birch.common.Instance;
import org.codesketch.birch.common.StringUtils;

import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2Client;
import com.amazonaws.services.ec2.model.InstanceStateChange;
import com.amazonaws.services.ec2.model.Reservation;

/**
 * Encapsulate the AWS EC2 client and expose all the method to deal with AWS.
 * @author Quirino Brizi
 *
 */
public class Birch {
	
	private transient AmazonEC2Client ec2;
	
	/**
	 * Create a new {@link Birch} instance.
	 * @param accessKey the AWS access key
	 * @param secretKey the AWS secret key
	 * @param endpoint the AWS end point
	 */
	private Birch(final String accessKey, final String secretKey, 
			final String endpoint) {
		this(accessKey, secretKey, endpoint, null);
	}
	/**
	 * Create a new {@link Birch} instance.
	 * @param accessKey the AWS access key
	 * @param secretKey the AWS secret key
	 * @param endpoint the AWS end point
	 */
	private Birch(final String accessKey, final String secretKey, 
			final String endpoint, final Properties properties) {
		connect(accessKey, secretKey, endpoint, properties);
	}
	/**
	 * Exposes the internal AWS EC2 client instance.
	 * @return
	 */
	AmazonEC2 client() {
		return ec2;
	}
	public void setEndpoint(final String endpoint) {
		if(!StringUtils.empty(endpoint)) {
			ec2.setEndpoint(endpoint);
		}
	}
	/**
	 * Sends an instances run request to AWS EC2
	 * @param request the run request specifications
	 * @return a response containing the AWS EC2 information
	 */
	public BirchResponse<Reservation> run(final BirchRequest request) {
		return Command.run(this, request);
	}
	/**
	 * Sends an instances terminate request to AWS EC2
	 * @param instances the instances to have to terminate
	 * @return a response wrapping the AWS EC2 {@link InstanceStateChange} information
	 */
	public BirchResponse<Reservation> terminate(final Set<Instance> instances) {
		final BirchRequest request = new BirchRequest();
		request.put(RequestField.TERMINATE_INSTANCES_INSTANCE_IDS, CommandUtils.getInstancesIdForTerminate(instances));
		return Command.terminate(this, request);
	}

	public static Birch with(
			final String accessKey, final String secretKey) {
		return new Birch(accessKey, secretKey, null);
	}
	public static Birch with(
			final String accessKey, final String secretKey, final String endpoint) {
		return new Birch(accessKey, secretKey, endpoint);
	}
	
	/**
	 * Create a new {@link AWSCredentials} object based on the given keys.
	 * @param accessKey the access key
	 * @param secretKey the secret key
	 * @return {@link AWSCredentials} object.
	 */
	private AWSCredentials credentials(
			final String accessKey, final String secretKey) {
		
		if(!StringUtils.empty(accessKey, secretKey)) {
			// here only if both access and secret key are not null
			return new BasicAWSCredentials(accessKey, secretKey);
		} else {
			throw new InvalidParameterException("Access key and secret key must be not null");
		}
	}
	/**
	 * Connect to AWS EC2
	 * @param accessKey the account access key
	 * @param secretKey the account secret key
	 * @param endpoint the AWS zone end point
	 * @param properties
	 */
	private void connect(final String accessKey, final String secretKey, 
			final String endpoint, final Properties properties) {
		if(!StringUtils.empty(accessKey, secretKey)) {
			ec2=new AmazonEC2Client(credentials(accessKey, secretKey));
			setEndpoint(endpoint);
			// TODO create connection properties based on the given properties
		}
	}
}
